import CryptoJS from 'crypto-js';

/**
 * 文件工具类 - 前端文件分片处理
 */
class FileUtils {
  /**
   * 计算文件MD5（使用CryptoJS）
   */
  static async calculateFileMD5(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = (e) => {
        try {
          const buffer = e.target.result;
          const wordArray = FileUtils.arrayBufferToWordArray(buffer);
          const md5 = CryptoJS.MD5(wordArray).toString();
          resolve(md5);
        } catch (error) {
          reject(error);
        }
      };

      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * ArrayBuffer转WordArray（CryptoJS格式）
   */
  static arrayBufferToWordArray(arrayBuffer) {
    const u8 = new Uint8Array(arrayBuffer);
    const len = u8.length;
    const words = [];

    for (let i = 0; i < len; i++) {
      words[i >>> 2] |= (u8[i] & 0xff) << (24 - (i % 4) * 8);
    }

    return CryptoJS.lib.WordArray.create(words, len);
  }

  /**
   * 分片文件
   */
  static sliceFile(file, chunkSize) {
    const chunks = [];
    const totalChunks = Math.ceil(file.size / chunkSize);

    for (let i = 0; i < totalChunks; i++) {
      const start = i * chunkSize;
      const end = Math.min(start + chunkSize, file.size);
      const chunk = file.slice(start, end);
      chunks.push({
        chunkNumber: i + 1,
        blob: chunk,
        start: start,
        end: end,
        size: end - start
      });
    }

    return chunks;
  }

  /**
   * 创建文件分片FormData
   */
  static createChunkFormData(file, chunk, chunkData) {
    const formData = new FormData();

    // 添加分片文件
    formData.append('chunk', chunk.blob, `chunk_${chunk.chunkNumber}`);

    // 添加分片元数据
    Object.keys(chunkData).forEach(key => {
      formData.append(key, chunkData[key]);
    });

    return formData;
  }

  /**
   * 验证文件类型
   */
  static validateFileType(file, allowedTypes) {
    if (!allowedTypes || allowedTypes.length === 0) {
      return true;
    }

    const fileType = file.type.toLowerCase();
    return allowedTypes.some(type => {
      if (type.startsWith('.')) {
        // 文件扩展名验证
        const fileName = file.name.toLowerCase();
        return fileName.endsWith(type.toLowerCase());
      } else {
        // MIME类型验证
        return fileType.includes(type.toLowerCase());
      }
    });
  }

  /**
   * 验证文件大小
   */
  static validateFileSize(file, maxSize) {
    return file.size <= maxSize;
  }

  /**
   * 获取文件扩展名
   */
  static getFileExtension(filename) {
    return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2);
  }

  /**
   * 获取文件MIME类型
   */
  static getFileMimeType(file) {
    return file.type || 'application/octet-stream';
  }

  /**
   * 格式化文件大小
   */
  static formatFileSize(bytes, decimals = 2) {
    if (bytes === 0) return '0 Bytes';

    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];

    const i = Math.floor(Math.log(bytes) / Math.log(k));

    return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  }

  /**
   * 生成唯一文件名
   */
  static generateUniqueFileName(originalName) {
    const timestamp = Date.now();
    const random = Math.random().toString(36).substring(2, 8);
    const extension = this.getFileExtension(originalName);

    return `${timestamp}_${random}.${extension}`;
  }

  /**
   * 创建文件下载链接
   */
  static createDownloadLink(blob, filename) {
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    return { url, element: a };
  }

  /**
   * 触发文件下载
   */
  static triggerDownload(blob, filename) {
    const { url, element } = this.createDownloadLink(blob, filename);
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);

    // 清理URL
    setTimeout(() => URL.revokeObjectURL(url), 100);
  }

  /**
   * 读取文件为DataURL
   */
  static readFileAsDataURL(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  }

  /**
   * 读取文件为文本
   */
  static readFileAsText(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
      reader.readAsText(file);
    });
  }

  /**
   * 读取文件为ArrayBuffer
   */
  static readFileAsArrayBuffer(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * 创建文件缩略图
   */
  static createFileThumbnail(file, maxWidth = 200, maxHeight = 200) {
    return new Promise((resolve, reject) => {
      if (!file.type.startsWith('image/')) {
        resolve(null);
        return;
      }

      const img = new Image();
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');

      img.onload = () => {
        // 计算缩略图尺寸
        let { width, height } = img;

        if (width > height) {
          if (width > maxWidth) {
            height *= maxWidth / width;
            width = maxWidth;
          }
        } else {
          if (height > maxHeight) {
            width *= maxHeight / height;
            height = maxHeight;
          }
        }

        canvas.width = width;
        canvas.height = height;

        ctx.drawImage(img, 0, 0, width, height);
        resolve(canvas.toDataURL('image/jpeg', 0.8));
      };

      img.onerror = reject;
      img.src = URL.createObjectURL(file);
    });
  }

  /**
   * 压缩图片文件
   */
  static compressImage(file, quality = 0.8, maxWidth = 1920, maxHeight = 1080) {
    return new Promise((resolve, reject) => {
      if (!file.type.startsWith('image/')) {
        resolve(file);
        return;
      }

      const img = new Image();
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');

      img.onload = () => {
        let { width, height } = img;

        // 等比例缩放
        if (width > maxWidth || height > maxHeight) {
          const ratio = Math.min(maxWidth / width, maxHeight / height);
          width *= ratio;
          height *= ratio;
        }

        canvas.width = width;
        canvas.height = height;

        ctx.drawImage(img, 0, 0, width, height);

        canvas.toBlob(blob => {
          resolve(new File([blob], file.name, {
            type: 'image/jpeg',
            lastModified: Date.now()
          }));
        }, 'image/jpeg', quality);
      };

      img.onerror = reject;
      img.src = URL.createObjectURL(file);
    });
  }

  /**
   * 计算上传/下载速度
   */
  static calculateSpeed(loaded, total, startTime) {
    const elapsed = (Date.now() - startTime) / 1000; // 转换为秒
    const speed = loaded / elapsed; // bytes per second

    if (speed === 0) return '0 B/s';

    const units = ['B/s', 'KB/s', 'MB/s', 'GB/s'];
    let unitIndex = 0;
    let currentSpeed = speed;

    while (currentSpeed >= 1024 && unitIndex < units.length - 1) {
      currentSpeed /= 1024;
      unitIndex++;
    }

    return `${currentSpeed.toFixed(2)} ${units[unitIndex]}`;
  }

  /**
   * 计算剩余时间
   */
  static calculateRemainingTime(loaded, total, startTime) {
    if (loaded === 0) return '计算中...';

    const elapsed = (Date.now() - startTime) / 1000; // 已用时间（秒）
    const speed = loaded / elapsed; // 速度（bytes/秒）
    const remaining = total - loaded; // 剩余字节数
    const remainingSeconds = remaining / speed; // 剩余时间（秒）

    if (remainingSeconds === Infinity || isNaN(remainingSeconds)) {
      return '未知';
    }

    return this.formatTime(remainingSeconds);
  }

/**
   * 格式化时间（秒转为可读格式）
   */
  static formatTime(seconds) {
    if (seconds < 60) {
      return `${Math.ceil(seconds)}秒`;
    } else if (seconds < 3600) {
      return `${Math.ceil(seconds / 60)}分钟`;
    } else {
      return `${Math.ceil(seconds / 3600)}小时`;
    }
  }

  /**
   * 验证文件名安全性
   */
  static sanitizeFileName(filename) {
    return filename
      .replace(/[^a-zA-Z0-9\u4e00-\u9fa5\-_.]/g, '_') // 替换非法字符
      .replace(/_{2,}/g, '_') // 替换连续下划线
      .replace(/^\.+|\.+$/g, '') // 移除首尾点号
      .substring(0, 255); // 限制长度
  }

  /**
   * 获取文件图标类型
   */
  static getFileIconType(filename) {
    const ext = this.getFileExtension(filename).toLowerCase();
    const iconMap = {
      // 图片
      'jpg': 'image', 'jpeg': 'image', 'png': 'image', 'gif': 'image',
      'bmp': 'image', 'webp': 'image', 'svg': 'image',

      // 视频
      'mp4': 'video', 'avi': 'video', 'mov': 'video', 'wmv': 'video',
      'flv': 'video', 'mkv': 'video', 'webm': 'video',

      // 音频
      'mp3': 'audio', 'wav': 'audio', 'ogg': 'audio', 'flac': 'audio',
      'aac': 'audio', 'm4a': 'audio',

      // 文档
      'pdf': 'pdf',
      'doc': 'word', 'docx': 'word',
      'xls': 'excel', 'xlsx': 'excel',
      'ppt': 'powerpoint', 'pptx': 'powerpoint',
      'txt': 'text', 'md': 'text',

      // 压缩包
      'zip': 'archive', 'rar': 'archive', '7z': 'archive', 'tar': 'archive',
      'gz': 'archive',

      // 代码
      'js': 'code', 'html': 'code', 'css': 'code', 'json': 'code',
      'xml': 'code', 'java': 'code', 'py': 'code', 'cpp': 'code'
    };

    return iconMap[ext] || 'file';
  }

  /**
   * 获取文件类型分类
   */
  static getFileCategory(filename) {
    const iconType = this.getFileIconType(filename);
    const categoryMap = {
      'image': 'image',
      'video': 'video',
      'audio': 'audio',
      'pdf': 'document',
      'word': 'document',
      'excel': 'document',
      'powerpoint': 'document',
      'text': 'document',
      'code': 'document',
      'archive': 'archive',
      'file': 'other'
    };

    return categoryMap[iconType] || 'other';
  }

  /**
   * 批量处理文件
   */
  static async processFilesInBatch(files, processor, batchSize = 5) {
    const results = [];

    for (let i = 0; i < files.length; i += batchSize) {
      const batch = files.slice(i, i + batchSize);
      const batchPromises = batch.map(file => processor(file));
      const batchResults = await Promise.all(batchPromises);
      results.push(...batchResults);
    }

    return results;
  }

  /**
   * 创建文件哈希（用于去重）
   */
  static async createFileHash(file, algorithm = 'SHA-256') {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();

      reader.onload = async (e) => {
        try {
          const buffer = e.target.result;
          const hashBuffer = await crypto.subtle.digest(algorithm, buffer);
          const hashArray = Array.from(new Uint8Array(hashBuffer));
          const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
          resolve(hashHex);
        } catch (error) {
          reject(error);
        }
      };

      reader.onerror = reject;
      reader.readAsArrayBuffer(file);
    });
  }

  /**
   * 检测文件是否相同（基于内容哈希）
   */
  static async isSameFile(file1, file2) {
    if (file1.size !== file2.size) return false;

    const [hash1, hash2] = await Promise.all([
      this.createFileHash(file1),
      this.createFileHash(file2)
    ]);

    return hash1 === hash2;
  }

  /**
   * 创建文件预览URL
   */
  static createPreviewURL(file) {
    return URL.createObjectURL(file);
  }

  /**
   * 释放预览URL
   */
  static revokePreviewURL(url) {
    URL.revokeObjectURL(url);
  }

  /**
   * 获取文件信息统计
   */
  static getFilesStats(files) {
    const stats = {
      totalCount: files.length,
      totalSize: 0,
      byType: {},
      bySize: {
        small: 0,    // < 1MB
        medium: 0,   // 1MB - 10MB
        large: 0,    // 10MB - 100MB
        huge: 0      // > 100MB
      }
    };

    files.forEach(file => {
      // 总大小
      stats.totalSize += file.size;

      // 按类型统计
      const type = this.getFileCategory(file.name);
      stats.byType[type] = (stats.byType[type] || 0) + 1;

      // 按大小统计
      const sizeMB = file.size / (1024 * 1024);
      if (sizeMB < 1) stats.bySize.small++;
      else if (sizeMB < 10) stats.bySize.medium++;
      else if (sizeMB < 100) stats.bySize.large++;
      else stats.bySize.huge++;
    });

    return stats;
  }

  /**
   * 生成文件上传表单数据
   */
  static createUploadFormData(files, additionalData = {}) {
    const formData = new FormData();

    // 添加文件
    if (Array.isArray(files)) {
      files.forEach((file, index) => {
        formData.append('files', file);
      });
    } else {
      formData.append('file', files);
    }

    // 添加额外数据
    Object.keys(additionalData).forEach(key => {
      formData.append(key, additionalData[key]);
    });

    return formData;
  }

  /**
   * 模拟文件上传进度（用于测试）
   */
  static simulateUploadProgress(duration = 5000, onProgress) {
    return new Promise(resolve => {
      const startTime = Date.now();
      const interval = setInterval(() => {
        const elapsed = Date.now() - startTime;
        const progress = Math.min((elapsed / duration) * 100, 100);

        onProgress(progress);

        if (progress >= 100) {
          clearInterval(interval);
          resolve();
        }
      }, 100);
    });
  }

  /**
   * 检查浏览器文件API支持情况
   */
  static checkBrowserSupport() {
    const supports = {
      fileReader: !!window.FileReader,
      blob: !!window.Blob,
      formData: !!window.FormData,
      fileAPI: !!window.File,
      crypto: !!window.crypto && !!crypto.subtle,
      worker: !!window.Worker,
      indexedDB: !!window.indexedDB
    };

    return {
      ...supports,
      allSupported: Object.values(supports).every(Boolean)
    };
  }

  /**
   * 创建文件下载管理器
   */
  static createDownloadManager() {
    const downloads = new Map();

    return {
      addDownload(id, download) {
        downloads.set(id, download);
      },

      getDownload(id) {
        return downloads.get(id);
      },

      removeDownload(id) {
        downloads.delete(id);
      },

      pauseAll() {
        downloads.forEach(download => {
          if (download.pause) download.pause();
        });
      },

      resumeAll() {
        downloads.forEach(download => {
          if (download.resume) download.resume();
        });
      },

      cancelAll() {
        downloads.forEach(download => {
          if (download.cancel) download.cancel();
        });
        downloads.clear();
      },

      getDownloads() {
        return Array.from(downloads.values());
      }
    };
  }
}

export default FileUtils;
